const rateLimit = require('express-rate-limit');
const crypto = require('crypto');
const config = require('../config/wechat');
const helmet = require('helmet');
const csrf = require('csurf');
const xss = require('xss-clean');
const logger = require('../utils/logger');

// 安全头设置
const securityHeaders = helmet({
    contentSecurityPolicy: {
        directives: {
            defaultSrc: ["'self'"],
            scriptSrc: ["'self'", "'unsafe-inline'", '*.weixin.qq.com'],
            styleSrc: ["'self'", "'unsafe-inline'"],
            imgSrc: ["'self'", 'data:', '*.wx.qq.com'],
            connectSrc: ["'self'", '*.weixin.qq.com']
        }
    }
});

// 速率限制 (分层限制)
const apiLimiter = rateLimit({
    windowMs: 60 * 1000, // 1分钟
    max: (req) => {
        // API端点更严格的限制
        if (req.path.startsWith('/api/')) return 30;
        // 普通端点限制
        return 100;
    },
    message: '请求过于频繁，请稍后再试',
    skip: (req) => {
        // 白名单路由不限制
        return ['/health', '/wechat'].includes(req.path);
    },
    handler: (req, res) => {
        logger.warn('速率限制触发', {
            path: req.path,
            ip: req.ip,
            method: req.method
        });
        res.status(429).json({ 
            code: 429, 
            message: '请求过于频繁，请稍后再试' 
        });
    }
});

// CSRF防护
const csrfProtection = csrf({
    cookie: true,
    value: (req) => {
        // 从header或body中获取CSRF token
        return req.headers['x-csrf-token'] || req.body._csrf;
    }
});

// XSS防护
const xssProtection = xss();

// 请求签名验证
const validateSignature = (req, res, next) => {
    try {
        const { signature, timestamp, nonce } = req.query;
        
        if (!signature || !timestamp || !nonce) {
            logger.warn('缺少签名参数', { 
                path: req.path,
                ip: req.ip 
            });
            return res.status(400).json({ 
                code: 400, 
                message: '缺少签名参数',
                required: ['signature', 'timestamp', 'nonce']
            });
        }

        // 验证时间戳格式和有效性 (5分钟内)
        if (!/^\d{10,13}$/.test(timestamp)) {
            logger.warn('无效的时间戳格式', { 
                timestamp,
                path: req.path
            });
            return res.status(400).json({ 
                code: 400, 
                message: '无效的时间戳格式' 
            });
        }

        const requestTime = parseInt(timestamp);
        const now = Date.now();
        const timeDiff = Math.abs(now - requestTime);
        
        if (timeDiff > 300000) { // 5分钟
            logger.warn('签名已过期', { 
                timestamp,
                timeDiff,
                path: req.path
            });
            return res.status(400).json({ 
                code: 400, 
                message: '签名已过期',
                maxAge: '5分钟'
            });
        }

        // 生成签名
        const tmpArr = [config.apiSecret, timestamp, nonce].sort();
        const tmpStr = tmpArr.join('');
        const sha1 = crypto.createHash('sha1').update(tmpStr).digest('hex');
        
        if (sha1 !== signature) {
            logger.warn('签名验证失败', {
                expected: sha1,
                received: signature,
                clientIp: req.ip,
                path: req.path
            });
            return res.status(403).json({ 
                code: 403, 
                message: '签名验证失败' 
            });
        }

        // 记录验证成功的请求
        logger.debug('签名验证通过', {
            timestamp,
            nonce,
            clientIp: req.ip,
            path: req.path
        });

        next();
    } catch (err) {
        logger.error('签名验证异常', {
            error: err.message,
            stack: err.stack,
            path: req.path
        });
        res.status(500).json({ 
            code: 500, 
            message: '服务器错误' 
        });
    }
};

// 敏感操作验证
const sensitiveOperationCheck = (req, res, next) => {
    if (['POST', 'PUT', 'DELETE'].includes(req.method)) {
        const verificationCode = req.headers['x-verification-code'] || req.body.verificationCode;
        if (!verificationCode) {
            logger.warn('缺少二次验证码', {
                path: req.path,
                method: req.method
            });
            return res.status(403).json({
                code: 403,
                message: '此操作需要二次验证'
            });
        }
        // 这里可以添加验证码校验逻辑
    }
    next();
};

module.exports = {
    securityHeaders,
    apiLimiter,
    csrfProtection,
    xssProtection,
    validateSignature,
    sensitiveOperationCheck
};